/**
 * Copyright (C) 2021 - 2031 O-Cubes Co., Ltd.
 */

/****************************************************************
 *  @file    device_uart.c
 *  @brief   Designware uart device adapter layer
 *  @version v1.0
 *  @date    03. Apr. 2023
 *  @author  liuchao
 ****************************************************************/

#include "mem_map_table.h"
#include "device_uart.h"
#include "dw_uart.h"
#include "crg.h"
#include "irq.h"

/**
 * @name	DesignWare UART 0 Object Instantiation
 * @{
 */
#if (USE_DW_UART_0)
static void dw_uart_0_isr(void *ptr);
#define DW_UART_0_REGBASE       (MEM_MAP_UART0_BASE_ADDR)    /*!< designware uart 0 baseaddr */
#define DW_UART_0_INTNO         (UART0_IRQn)            /*!< designware uart 0 interrupt number  */
#define DW_UART_0_FIFO_LEN      (DW_UART_FIFO_LEN)      /*!< designware uart 0 fifo(tx/rx) length  */

DEV_UART dw_uart_0;                                     /*!< designware uart object */
DW_UART_CTRL dw_uart_0_ctrl = {                         /*!< designware uart 0 ctrl */
	DW_UART_0_ID, 0, 0, DW_UART_0_INTNO, (irq_handler)dw_uart_0_isr,
	DW_UART_0_FIFO_LEN, DW_UART_0_FIFO_LEN, 0
};

/** designware uart 0 open */
static int32_t dw_uart_0_open(uint32_t baud)
{
	return dw_uart_open(&dw_uart_0, baud);
}

/** designware uart 0 close */
static int32_t dw_uart_0_close(void)
{
	return dw_uart_close(&dw_uart_0);
}

/** designware uart 0 control */
static int32_t dw_uart_0_control(uint32_t ctrl_cmd, void *param)
{
	return dw_uart_control(&dw_uart_0, ctrl_cmd, param);
}

/** designware uart 0 write */
static int32_t dw_uart_0_write(const void *data, uint32_t len)
{
	return dw_uart_write(&dw_uart_0, data, len);
}

/** designware uart 0 close */
static int32_t dw_uart_0_read(void *data, uint32_t len)
{
	return dw_uart_read(&dw_uart_0, data, len);
}

/** designware uart 0 interrupt rountine */
static void dw_uart_0_isr(void *ptr)
{
	dw_uart_isr(&dw_uart_0, ptr);
}

/** install designware uart 0 to system */
static void dw_uart_0_install(void)
{
	uint32_t uart_abs_base = 0;
	DEV_UART *dw_uart_ptr = &dw_uart_0;
	DEV_UART_INFO *dw_uart_info_ptr = &(dw_uart_0.uart_info);
	DW_UART_CTRL *dw_uart_ctrl_ptr = &dw_uart_0_ctrl;

	/**
	 * get absolute designware base address
	 */
	uart_abs_base = (uint32_t)DW_UART_0_REGBASE;
	dw_uart_ctrl_ptr->dw_uart_regbase = uart_abs_base;
	dw_uart_ctrl_ptr->dw_apb_bus_freq = get_mod_clk_rate(CRG_MOD_UART0);
	dw_uart_ctrl_ptr->intno = UART0_IRQn;
	dw_uart_ctrl_ptr->dw_uart_int_handler = dw_uart_0_isr;

	/** uart info init */
	dw_uart_info_ptr->uart_ctrl = (void *)dw_uart_ctrl_ptr;
	dw_uart_info_ptr->opn_cnt = 0;
	dw_uart_info_ptr->status = 0;
	dw_uart_info_ptr->baudrate = UART_BAUDRATE_115200;

	/** uart dev init */
	dw_uart_ptr->uart_open = dw_uart_0_open;
	dw_uart_ptr->uart_close = dw_uart_0_close;
	dw_uart_ptr->uart_control = dw_uart_0_control;
	dw_uart_ptr->uart_write = dw_uart_0_write;
	dw_uart_ptr->uart_read = dw_uart_0_read;

}
#endif /* USE_DW_UART_0 */
/** @} end of name */

/**
 * @name	DesignWare UART 1 Object Instantiation
 * @{
 */
#if (USE_DW_UART_1)
static void dw_uart_1_isr(void *ptr);
#define DW_UART_1_REGBASE       (MEM_MAP_UART1_BASE_ADDR)    /*!< designware uart 1 baseaddr */
#define DW_UART_1_INTNO         (UART1_IRQn)            /*!< designware uart 1 interrupt number  */
#define DW_UART_1_FIFO_LEN      (DW_UART_FIFO_LEN)      /*!< designware uart 1 fifo(tx/rx) length  */

DEV_UART dw_uart_1;                                     /*!< designware uart 1 object */
DW_UART_CTRL dw_uart_1_ctrl = {                         /*!< designware uart 1 ctrl */
	DW_UART_1_ID, 0, 0, DW_UART_1_INTNO, (irq_handler)dw_uart_1_isr,
	DW_UART_1_FIFO_LEN, DW_UART_1_FIFO_LEN, 0
};

/** designware uart 1 open */
static int32_t dw_uart_1_open(uint32_t baud)
{
	return dw_uart_open(&dw_uart_1, baud);
}

/** designware uart 1 close */
static int32_t dw_uart_1_close(void)
{
	return dw_uart_close(&dw_uart_1);
}

/** designware uart 1 control */
static int32_t dw_uart_1_control(uint32_t ctrl_cmd, void *param)
{
	return dw_uart_control(&dw_uart_1, ctrl_cmd, param);
}

/** designware uart 1 write */
static int32_t dw_uart_1_write(const void *data, uint32_t len)
{
	return dw_uart_write(&dw_uart_1, data, len);
}

/** designware uart 1 close */
static int32_t dw_uart_1_read(void *data, uint32_t len)
{
	return dw_uart_read(&dw_uart_1, data, len);
}

/** designware uart 1 interrupt routine */
static void dw_uart_1_isr(void *ptr)
{
	dw_uart_isr(&dw_uart_1, ptr);
}

/** install designware uart 1 to system */
static void dw_uart_1_install(void)
{
	uint32_t uart_abs_base = 0;
	DEV_UART *dw_uart_ptr = &dw_uart_1;
	DEV_UART_INFO *dw_uart_info_ptr = &(dw_uart_1.uart_info);
	DW_UART_CTRL *dw_uart_ctrl_ptr = &dw_uart_1_ctrl;

	/**
	 * get absolute designware base address
	 */
	uart_abs_base = (uint32_t)DW_UART_1_REGBASE;
	dw_uart_ctrl_ptr->dw_uart_regbase = uart_abs_base;
	dw_uart_ctrl_ptr->dw_apb_bus_freq = get_mod_clk_rate(CRG_MOD_UART1);
	dw_uart_ctrl_ptr->intno = UART1_IRQn;
	dw_uart_ctrl_ptr->dw_uart_int_handler = dw_uart_1_isr;

	/** uart info init */
	dw_uart_info_ptr->uart_ctrl = (void *)dw_uart_ctrl_ptr;
	dw_uart_info_ptr->opn_cnt = 0;
	dw_uart_info_ptr->status = 0;
	dw_uart_info_ptr->baudrate = UART_BAUDRATE_115200;

	/** uart dev init */
	dw_uart_ptr->uart_open = dw_uart_1_open;
	dw_uart_ptr->uart_close = dw_uart_1_close;
	dw_uart_ptr->uart_control = dw_uart_1_control;
	dw_uart_ptr->uart_write = dw_uart_1_write;
	dw_uart_ptr->uart_read = dw_uart_1_read;
}
#endif /* USE_DW_UART_1 */
/** @} end of name */

/**
 * @name	DesignWare UART 2 Object Instantiation
 * @{
 */
#if (USE_DW_UART_2)
static void dw_uart_2_isr(void *ptr);
#define DW_UART_2_REGBASE       (MEM_MAP_UART2_BASE_ADDR)    /*!< designware uart 2 baseaddr */
#define DW_UART_2_INTNO         (UART2_IRQn)            /*!< designware uart 2 interrupt number  */
#define DW_UART_2_FIFO_LEN      (DW_UART_FIFO_LEN)      /*!< designware uart 2 fifo(tx/rx) length  */

DEV_UART dw_uart_2;                                     /*!< designware uart 2 object */
DW_UART_CTRL dw_uart_2_ctrl = {                         /*!< designware uart 2 ctrl */
	DW_UART_2_ID, 0, 0, DW_UART_2_INTNO, (irq_handler)dw_uart_2_isr,
	DW_UART_2_FIFO_LEN, DW_UART_2_FIFO_LEN, 0
};

/** designware uart 2 open */
static int32_t dw_uart_2_open(uint32_t baud)
{
	return dw_uart_open(&dw_uart_2, baud);
}

/** designware uart 2 close */
static int32_t dw_uart_2_close(void)
{
	return dw_uart_close(&dw_uart_2);
}

/** designware uart 2 control */
static int32_t dw_uart_2_control(uint32_t ctrl_cmd, void *param)
{
	return dw_uart_control(&dw_uart_2, ctrl_cmd, param);
}

/** designware uart 2 write */
static int32_t dw_uart_2_write(const void *data, uint32_t len)
{
	return dw_uart_write(&dw_uart_2, data, len);
}

/** designware uart 2 close */
static int32_t dw_uart_2_read(void *data, uint32_t len)
{
	return dw_uart_read(&dw_uart_2, data, len);
}

/** designware uart 2 interrupt routine */
static void dw_uart_2_isr(void *ptr)
{
	dw_uart_isr(&dw_uart_2, ptr);
}

/** install designware uart 2 to system */
static void dw_uart_2_install(void)
{
	uint32_t uart_abs_base = 0;
	DEV_UART *dw_uart_ptr = &dw_uart_2;
	DEV_UART_INFO *dw_uart_info_ptr = &(dw_uart_2.uart_info);
	DW_UART_CTRL *dw_uart_ctrl_ptr = &dw_uart_2_ctrl;

	/**
	 * get absolute designware base address
	 */
	uart_abs_base = (uint32_t)DW_UART_2_REGBASE;
	dw_uart_ctrl_ptr->dw_uart_regbase = uart_abs_base;
	dw_uart_ctrl_ptr->dw_apb_bus_freq = get_mod_clk_rate(CRG_MOD_UART2);
	dw_uart_ctrl_ptr->intno = UART2_IRQn;
	dw_uart_ctrl_ptr->dw_uart_int_handler = dw_uart_2_isr;

	/** uart info init */
	dw_uart_info_ptr->uart_ctrl = (void *)dw_uart_ctrl_ptr;
	dw_uart_info_ptr->opn_cnt = 0;
	dw_uart_info_ptr->status = 0;
	dw_uart_info_ptr->baudrate = UART_BAUDRATE_115200;

	/** uart dev init */
	dw_uart_ptr->uart_open = dw_uart_2_open;
	dw_uart_ptr->uart_close = dw_uart_2_close;
	dw_uart_ptr->uart_control = dw_uart_2_control;
	dw_uart_ptr->uart_write = dw_uart_2_write;
	dw_uart_ptr->uart_read = dw_uart_2_read;
}
#endif /* USE_DW_UART_2 */
/** @} end of name */

/**
 * @name DesignWare UART 3 Object Instantiation
 * @{
 */
#if (USE_DW_UART_3)
static void dw_uart_3_isr(void *ptr);
#define DW_UART_3_REGBASE       (MEM_MAP_UART3_BASE_ADDR)    /*!< designware uart 3 baseaddr */
#define DW_UART_3_INTNO         (UART3_IRQn)            /*!< designware uart 3 interrupt number  */
#define DW_UART_3_FIFO_LEN      (0)                     /*!< designware uart 3 fifo(tx/rx) length  */

DEV_UART dw_uart_3;                                     /*!< designware uart 3 object */
DW_UART_CTRL dw_uart_3_ctrl = {                         /*!< designware uart 3 ctrl */
	DW_UART_3_ID, 0, 0, DW_UART_3_INTNO, (irq_handler)dw_uart_3_isr,
	DW_UART_3_FIFO_LEN, DW_UART_3_FIFO_LEN, 0
};

/** designware uart 3 open */
static int32_t dw_uart_3_open(uint32_t baud)
{
	return dw_uart_open(&dw_uart_3, baud);
}

/** designware uart 3 close */
static int32_t dw_uart_3_close(void)
{
	return dw_uart_close(&dw_uart_3);
}

/** designware uart 3 control */
static int32_t dw_uart_3_control(uint32_t ctrl_cmd, void *param)
{
	return dw_uart_control(&dw_uart_3, ctrl_cmd, param);
}

/** designware uart 3 write */
static int32_t dw_uart_3_write(const void *data, uint32_t len)
{
	return dw_uart_write(&dw_uart_3, data, len);
}

/** designware uart 3 close */
static int32_t dw_uart_3_read(void *data, uint32_t len)
{
	return dw_uart_read(&dw_uart_3, data, len);
}

/** designware uart 3 interrupt routine */
static void dw_uart_3_isr(void *ptr)
{
	dw_uart_isr(&dw_uart_3, ptr);
}

/** install designware uart 3 to system */
static void dw_uart_3_install(void)
{
	uint32_t uart_abs_base = 0;
	DEV_UART *dw_uart_ptr = &dw_uart_3;
	DEV_UART_INFO *dw_uart_info_ptr = &(dw_uart_3.uart_info);
	DW_UART_CTRL *dw_uart_ctrl_ptr = &dw_uart_3_ctrl;

	/**
	 * get absolute designware base address
	 */
	uart_abs_base = (uint32_t)DW_UART_3_REGBASE;
	dw_uart_ctrl_ptr->dw_uart_regbase = uart_abs_base;
	dw_uart_ctrl_ptr->dw_apb_bus_freq = get_mod_clk_rate(CRG_MOD_UART3);
	dw_uart_ctrl_ptr->intno = UART3_IRQn;
	dw_uart_ctrl_ptr->dw_uart_int_handler = dw_uart_3_isr;

	/** uart info init */
	dw_uart_info_ptr->uart_ctrl = (void *)dw_uart_ctrl_ptr;
	dw_uart_info_ptr->opn_cnt = 0;
	dw_uart_info_ptr->status = 0;
	dw_uart_info_ptr->baudrate = UART_BAUDRATE_115200;

	/** uart dev init */
	dw_uart_ptr->uart_open = dw_uart_3_open;
	dw_uart_ptr->uart_close = dw_uart_3_close;
	dw_uart_ptr->uart_control = dw_uart_3_control;
	dw_uart_ptr->uart_write = dw_uart_3_write;
	dw_uart_ptr->uart_read = dw_uart_3_read;
}
#endif /* USE_DW_UART_3 */
/** @} end of name */

/**
 * @name DesignWare UART 4 Object Instantiation
 * @{
 */
#if (USE_DW_UART_4)
static void dw_uart_4_isr(void *ptr);
#define DW_UART_4_REGBASE       (MEM_MAP_UART4_BASE_ADDR)    /*!< designware uart 4 baseaddr */
#define DW_UART_4_INTNO         (UART4_IRQn)            /*!< designware uart 4 interrupt number  */
#define DW_UART_4_FIFO_LEN      (0)                     /*!< designware uart 4 fifo(tx/rx) length  */

DEV_UART dw_uart_4;                                     /*!< designware uart 4 object */
DW_UART_CTRL dw_uart_4_ctrl = {                         /*!< designware uart 4 ctrl */
	DW_UART_4_ID, 0, 0, DW_UART_4_INTNO, (irq_handler)dw_uart_4_isr,
	DW_UART_4_FIFO_LEN, DW_UART_4_FIFO_LEN, 0
};

/** designware uart 4 open */
static int32_t dw_uart_4_open(uint32_t baud)
{
	return dw_uart_open(&dw_uart_4, baud);
}

/** designware uart 4 close */
static int32_t dw_uart_4_close(void)
{
	return dw_uart_close(&dw_uart_4);
}

/** designware uart 4 control */
static int32_t dw_uart_4_control(uint32_t ctrl_cmd, void *param)
{
	return dw_uart_control(&dw_uart_4, ctrl_cmd, param);
}

/** designware uart 4 write */
static int32_t dw_uart_4_write(const void *data, uint32_t len)
{
	return dw_uart_write(&dw_uart_4, data, len);
}

/** designware uart 4 close */
static int32_t dw_uart_4_read(void *data, uint32_t len)
{
	return dw_uart_read(&dw_uart_4, data, len);
}

/** designware uart 4 interrupt routine */
static void dw_uart_4_isr(void *ptr)
{
	dw_uart_isr(&dw_uart_4, ptr);
}

/** install designware uart 4 to system */
static void dw_uart_4_install(void)
{
	uint32_t uart_abs_base = 0;
	DEV_UART *dw_uart_ptr = &dw_uart_4;
	DEV_UART_INFO *dw_uart_info_ptr = &(dw_uart_4.uart_info);
	DW_UART_CTRL *dw_uart_ctrl_ptr = &dw_uart_4_ctrl;

	/**
	 * get absolute designware base address
	 */
	uart_abs_base = (uint32_t)DW_UART_4_REGBASE;
	dw_uart_ctrl_ptr->dw_uart_regbase = uart_abs_base;
	dw_uart_ctrl_ptr->dw_apb_bus_freq = get_mod_clk_rate(CRG_MOD_UART4);
	dw_uart_ctrl_ptr->intno = UART4_IRQn;
	dw_uart_ctrl_ptr->dw_uart_int_handler = dw_uart_4_isr;

	/** uart info init */
	dw_uart_info_ptr->uart_ctrl = (void *)dw_uart_ctrl_ptr;
	dw_uart_info_ptr->opn_cnt = 0;
	dw_uart_info_ptr->status = 0;
	dw_uart_info_ptr->baudrate = UART_BAUDRATE_115200;

	/** uart dev init */
	dw_uart_ptr->uart_open = dw_uart_4_open;
	dw_uart_ptr->uart_close = dw_uart_4_close;
	dw_uart_ptr->uart_control = dw_uart_4_control;
	dw_uart_ptr->uart_write = dw_uart_4_write;
	dw_uart_ptr->uart_read = dw_uart_4_read;
}
#endif /* USE_DW_UART_4 */
/** @} end of name */

/**
 * @brief	install all uart objects
 * @note	@b MUST be called during system init
 */
static void dw_uart_all_install(void)
{
#if (USE_DW_UART_0)
	dw_uart_0_install();
#endif
#if (USE_DW_UART_1)
	dw_uart_1_install();
#endif
#if (USE_DW_UART_2)
	dw_uart_2_install();
#endif
#if (USE_DW_UART_3)
	dw_uart_3_install();
#endif
#if (USE_DW_UART_4)
	dw_uart_4_install();
#endif
}

/** get one designware device structure */
DEV_UART_PTR uart_get_dev(int32_t uart_id)
{
	static uint32_t install_flag = 0;

	/* intall device objects */
	if (install_flag == 0) {
		install_flag = 1;
		dw_uart_all_install();
	}

	switch (uart_id) {
#if (USE_DW_UART_0)
		case DW_UART_0_ID:
			return &dw_uart_0;
#endif

#if (USE_DW_UART_1)
		case DW_UART_1_ID:
			return &dw_uart_1;
#endif

#if (USE_DW_UART_2)
		case DW_UART_2_ID:
			return &dw_uart_2;
#endif

#if (USE_DW_UART_3)
		case DW_UART_3_ID:
			return &dw_uart_3;
#endif

#if (USE_DW_UART_4)
		case DW_UART_4_ID:
			return &dw_uart_4;
#endif

		default:
			break;
	}

	return NULL;
}

